Skip to main content

Flocking Example - Containment

Continuning on from the previous example

We will create a containment behaviour from scratch.

Python​

Reynolds Containment​

import Rhino.Geometry as rg
import clr #.NET Common Language Runtime (CLR)
clr.AddReference("ABxM.Core.dll")
import ABxM.Core as abm;

class RectangleContainmentBehavior(abm.Behavior.BehaviorBase):
def __init__(self, weight):
self.Weight = weight
self.Rectangle = rg.Rectangle3d.Unset
self.Distance = 0

def Execute(self, agent):
boid = agent

newPosition = boid.Position + boid.Velocity
desired = boid.Velocity
steering = rg.Vector3d.Unset

if(self.Rectangle.IsValid):
if(self.Rectangle.Contains((newPosition)) == rg.PointContainment.Outside):
#project new position onto boundary
projPt = self.Rectangle.ClosestPoint(newPosition)
#extend position by to obtain target point
transVt = rg.Vector3d(projPt - newPosition)
transVt.Unitize()
# offset target point from boundary
target = self.Distance * transVt + projPt
desired = target - boid.Position

steering = desired - boid.Velocity
boid.AddForce(steering * self.Weight)


behavior = RectangleContainmentBehavior(W)
behavior.Rectangle = R
behavior.Distance = D
oBehavior = behavior

C#​

Reynolds Containment​

private void RunScript(Rectangle3d R, double D, double W, ref object oBehavior)
{

behavior.Weight = W;
behavior.Rectangle = R;
behavior.Distance = D;
oBehavior = behavior;

}

// <Custom additional code>

RectangleContainmentBehaviour behavior = new RectangleContainmentBehaviour(1.0);

public class RectangleContainmentBehaviour : BehaviorBase
{

public Rectangle3d Rectangle = Rectangle3d.Unset;
public double Distance = 0;

public RectangleContainmentBehaviour(double weight)
{
Weight = weight;
//iBox = B;
}

public override void Execute(AgentBase agent)
{
Boid boid = agent as Boid;

//======================================================================================================
// Task: Compute the "force" vector caused by this behavior and add it to the list "locoAgent.Force"
//======================================================================================================

Point3d newPosition = boid.Position + boid.Velocity;
Vector3d desired = boid.Velocity;
Vector3d steering = Vector3d.Unset;

/*
"To implement: first predict our character’s future position, if it is inside the allowed region
no corrective steering is necessary. Otherwise we steer towards the allowed region." (Reynolds 1999)
*/

if (Rectangle.IsValid){
if (Rectangle.Contains((newPosition)) == PointContainment.Outside){
// project new position onto boundary
Point3d projPt = Rectangle.ClosestPoint(newPosition);
// extend position by to obtain new target point
Vector3d transVt = (Vector3d) (projPt - newPosition);
transVt.Unitize();
Point3d target = Distance * transVt + projPt; // offset target point from boundary
desired = target - boid.Position;
steering = desired - boid.Velocity;
boid.AddForce(steering * Weight);
}

}
}
}

// </Custom additional code>

Shiffman Containment​

private void RunScript(Rectangle3d R, double W, ref object oBehavior)
{

behavior.Weight = W;
behavior.Rectangle = R;
oBehavior = behavior;

}

// <Custom additional code>


RectangleContainmentBehaviour behavior = new RectangleContainmentBehaviour(1.0);

public class RectangleContainmentBehaviour : BehaviorBase
{

public Rectangle3d Rectangle = Rectangle3d.Unset;

public RectangleContainmentBehaviour(double weight)
{
Weight = weight;
//iBox = B;
}

public override void Execute(AgentBase agent)
{
Boid boid = agent as Boid;

/* We shouldn't touch location and velocity directly, but there are some exceptions. Here we are doing so
as a quick and easy way to reverse the direction of our object when it reaches the edge. (Shiffman 2012) */

if (Rectangle.IsValid){
if (boid.Position.X < Rectangle.BoundingBox.Min.X){
boid.Velocity.X *= -1;
boid.Position.X = Rectangle.BoundingBox.Min.X;
} else if (boid.Position.X > Rectangle.BoundingBox.Max.X){
boid.Velocity.X *= -1;
boid.Position.X = Rectangle.BoundingBox.Max.X;
}
if (boid.Position.Y < Rectangle.BoundingBox.Min.Y){
boid.Velocity.Y *= -1;
boid.Position.Y = Rectangle.BoundingBox.Min.Y;
} else if (boid.Position.Y > Rectangle.BoundingBox.Max.Y){
boid.Velocity.Y *= -1;
boid.Position.Y = Rectangle.BoundingBox.Max.Y;
}
}
}
}

// <Custom additional code>